package javaproject;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.media.j3d.Canvas3D;
import javax.swing.Timer;

public class Rotator {
    static final int UP = 1;
    static final int DOWN = -1;
    static final int LEFT = 2;
    static final int RIGHT = -2;
    static final int NONE = 0;

    private boolean rotateLock = false;	    //旋轉鎖定一段時間
    private double initRadX, initRadY, initRadZ;   //記錄剛轉動時的初始角度
    private double offsetRadX, offsetRadY, offsetRadZ;   //轉到定點時其他軸的修正值
    private Timer fixedRotator;
    private Timer rotator;
    private double rotateSpeed;
    private int dir;
    private int elapsedTime;
    private Graph3D graph3D;
    private SpinGroup objSpin;
    private Debugger debugger;

    Rotator(final Graph3D graph3D, final SpinGroup objSpin, final Debugger debugger)
    {
	this.graph3D = graph3D;
	this.objSpin = objSpin;
	this.debugger = debugger;

	rotateSpeed = Config.rotateStep;

	rotator = new Timer(Config.rotateRefreshRate, new ActionListener()
	{
	    public void actionPerformed(ActionEvent e) {
		switch(dir)
		{
		    case UP:
			objSpin.rotX(rotateSpeed);
			break;
		    case DOWN:
			objSpin.rotX(-rotateSpeed);
			break;
		    case LEFT:
			objSpin.rotZ(rotateSpeed);
			break;
		    case RIGHT:
			objSpin.rotZ(-rotateSpeed);
			break;
		}
		if(debugger != null)
		{
		    debugger.update(debugger.T_rotX, objSpin.radX*360/(2*Math.PI));
		    debugger.update(debugger.T_rotY, objSpin.radY*360/(2*Math.PI));
		    debugger.update(debugger.T_rotZ, objSpin.radZ*360/(2*Math.PI));
		}
	    }
	});
	rotator.setRepeats(true);

	fixedRotator = new Timer(Config.rotateRefreshRate, new ActionListener()
	{
	    public void actionPerformed(ActionEvent e) {
		elapsedTime += Config.rotateRefreshRate;
		if(elapsedTime <= Config.rotatePeriod)
		{
		    switch(dir)
		    {
			case UP:
			    if(objSpin.radX < Math.PI)	//小於180，要轉到180
				objSpin.rotXto(initRadX*(1-elapsedTime/Config.rotatePeriod) + Math.PI*elapsedTime/Config.rotatePeriod);
			    else   //大於180，要轉到360(0)
				objSpin.rotXto(initRadX*(1-elapsedTime/Config.rotatePeriod) + 2*Math.PI*elapsedTime/Config.rotatePeriod);
			    //也把Y、Z慢慢轉到0
			    objSpin.rotYto(initRadY*(1-elapsedTime/Config.rotatePeriod) + offsetRadY*elapsedTime/Config.rotatePeriod);
			    objSpin.rotZto(initRadZ*(1-elapsedTime/Config.rotatePeriod) + offsetRadZ*elapsedTime/Config.rotatePeriod);
			    break;
			case DOWN:
			    if(objSpin.radX == 0)   //0要轉到180
			    {
				initRadX = 2*Math.PI;
				objSpin.rotXto(2*Math.PI - Math.PI*elapsedTime/Config.rotatePeriod);
			    }
			    else if(objSpin.radX > Math.PI)	//大於180，要轉到180
				objSpin.rotXto(initRadX*(1-elapsedTime/Config.rotatePeriod) + Math.PI*elapsedTime/Config.rotatePeriod);
			    else   //小於180，要轉到0
				objSpin.rotXto(initRadX*(1-elapsedTime/Config.rotatePeriod));
			    //也把Y、Z慢慢轉到0
			    objSpin.rotYto(initRadY*(1-elapsedTime/Config.rotatePeriod) + offsetRadY*elapsedTime/Config.rotatePeriod);
			    objSpin.rotZto(initRadZ*(1-elapsedTime/Config.rotatePeriod) + offsetRadZ*elapsedTime/Config.rotatePeriod);
			    break;
			case LEFT:
			    if(objSpin.radZ < Math.PI)	//小於180，要轉到180
				objSpin.rotZto(initRadZ*(1-elapsedTime/Config.rotatePeriod) + Math.PI*elapsedTime/Config.rotatePeriod);
			    else   //大於180，要轉到360(0)
				objSpin.rotZto(initRadZ*(1-elapsedTime/Config.rotatePeriod) + 2*Math.PI*elapsedTime/Config.rotatePeriod);
			    //也把X、Y慢慢轉到0
			    objSpin.rotXto(initRadX*(1-elapsedTime/Config.rotatePeriod) + offsetRadX*elapsedTime/Config.rotatePeriod);
			    objSpin.rotYto(initRadY*(1-elapsedTime/Config.rotatePeriod) + offsetRadY*elapsedTime/Config.rotatePeriod);
			    break;
			case RIGHT:
			    if(objSpin.radZ == 0)   //0要轉到180
			    {
				initRadZ = 2*Math.PI;
				objSpin.rotZto(2*Math.PI - Math.PI*elapsedTime/Config.rotatePeriod);
			    }
			    else if(objSpin.radZ > Math.PI)	//大於180，要轉到180
				objSpin.rotZto(initRadZ*(1-elapsedTime/Config.rotatePeriod) + Math.PI*elapsedTime/Config.rotatePeriod);
			    else   //小於180，要轉到0
				objSpin.rotZto(initRadZ*(1-elapsedTime/Config.rotatePeriod));
			    //也把X、Y慢慢轉到0
			    objSpin.rotXto(initRadX*(1-elapsedTime/Config.rotatePeriod) + offsetRadX*elapsedTime/Config.rotatePeriod);
			    objSpin.rotYto(initRadY*(1-elapsedTime/Config.rotatePeriod) + offsetRadY*elapsedTime/Config.rotatePeriod);
			    break;
		    }
		    if(debugger != null)
		    {
			debugger.update(debugger.T_rotX, objSpin.radX*360/(2*Math.PI));
			debugger.update(debugger.T_rotY, objSpin.radY*360/(2*Math.PI));
			debugger.update(debugger.T_rotZ, objSpin.radZ*360/(2*Math.PI));
		    }
		}
		else
		{
		    //回復狀態
		    rotateLock = false;
		    fixedRotator.stop();
		    graph3D.continueProceeding();
		}
	    }
	});
	fixedRotator.setRepeats(true);
    }
    public void rotate(int dir, double rotateSpeed) //小旋轉
    {
	rotate(false, dir, rotateSpeed);
    }
    public void rotate(int dir) //大旋轉
    {
	rotate(true, dir, rotateSpeed);
    }
    private void rotate(boolean fixedRotate, int dir, double rotateSpeed)
    {
        if(!rotateLock)
        {
	    //鎖住狀態
	    rotateLock = true;
	    this.dir = dir;

	    if(!fixedRotate)	//小旋轉
	    {
		this.rotateSpeed = rotateSpeed;
		rotator.restart();
	    }
	    else    //大旋轉
	    {
		{
		    //鎖住畫面
		    graph3D.stopProceeding();

		    elapsedTime = 0;
		    initRadX = objSpin.radX;
		    initRadY = objSpin.radY;
		    initRadZ = objSpin.radZ;
		    offsetRadX = 0;
		    offsetRadY = 0;
		    offsetRadZ = 0;
		    if(objSpin.radX >= Math.PI*3/2)
			offsetRadX = 2*Math.PI;
		    else if(objSpin.radX >= Math.PI*1/2 && objSpin.radX < Math.PI*3/2)
			offsetRadX = Math.PI;
		    if(objSpin.radY > Math.PI*3/2)
			offsetRadY = 2*Math.PI;
		    else if(objSpin.radY >= Math.PI*1/2 && objSpin.radY < Math.PI*3/2)
			offsetRadY = Math.PI;
		    if(objSpin.radZ > Math.PI*3/2)
			offsetRadZ = 2*Math.PI;
		    else if(objSpin.radZ >= Math.PI*1/2 && objSpin.radZ < Math.PI*3/2)
			offsetRadZ = Math.PI;
		    fixedRotator.restart();
		}
	    }
        }
    }
    public boolean stopRotate()
    {
	if(rotator.isRunning())
	{
	    rotateLock = false;
	    rotator.stop();
	    return true;
	}
	return false;
    }
    public void continueRotate()
    {
//	rotateLock = true;
	//if(graph3D.isPaused())
	//    rotator.start();
    }
}